﻿#region License
// Copyright 2007-2008 Rory Plaire (codekaizen@gmail.com)
/*
 * This license governs use of the accompanying software. If you use the software, you
 * accept this license. If you do not accept the license, do not use the software.
 * 
 * 1. Definitions
 * The terms "reproduce," "reproduction," "derivative works," and "distribution" have the
 * same meaning here as under U.S. copyright law.
 * A "contribution" is the original software, or any additions or changes to the software.
 * A "contributor" is any person that distributes its contribution under this license.
 * "Licensed patents" are a contributor's patent claims that read directly on its contribution.
 * 
 * 2. Grant of Rights
 * (A) Copyright Grant- Subject to the terms of this license, including the license conditions 
 *     and limitations in section 3, each contributor grants you a non-exclusive, worldwide, 
 *     royalty-free copyright license to reproduce its contribution, prepare derivative works 
 *     of its contribution, and distribute its contribution or any derivative works that you create.
 * (B) Patent Grant- Subject to the terms of this license, including the license conditions and 
 *     limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free 
 *     license under its licensed patents to make, have made, use, sell, offer for sale, import, 
 *     and/or otherwise dispose of its contribution in the software or derivative works of the 
 *     contribution in the software.
 * 
 * 3. Conditions and Limitations
 * (A) No Trademark License- This license does not grant you rights to use any contributors' 
 *     name, logo, or trademarks.
 * (B) If you bring a patent claim against any contributor over patents that you claim are 
 *     infringed by the software, your patent license from such contributor to the software 
 *     ends automatically.
 * (C) If you distribute any portion of the software, you must retain all copyright, patent, 
 *     trademark, and attribution notices that are present in the software.
 * (D) If you distribute any portion of the software in source code form, you may do so only under 
 *     this license by including a complete copy of this license with your distribution. If you 
 *     distribute any portion of the software in compiled or object code form, you may only do so 
 *     under a license that complies with this license.
 * (E) The software is licensed "as-is." You bear the risk of using it. The contributors give no 
 *     express warranties, guarantees or conditions. You may have additional consumer rights under 
 *     your local laws which this license cannot change. To the extent permitted under your local laws, 
 *     the contributors exclude the implied warranties of merchantability, fitness for a particular 
 *     purpose and non-infringement.
 * 
 */
#endregion

using System;
using System.Collections.Generic;

namespace NPack.Interfaces
{
    public interface IMatrixOperations<TComponent>
        where TComponent : IEquatable<TComponent>, IComparable<TComponent>, 
                           IComputable<TComponent>, IConvertible
    {
        /// <summary>
        /// Adds two matrixes and returns the result.
        /// </summary>
        /// <param name="lhs">First matrix to add.</param>
        /// <param name="rhs">Second matrix to add.</param>
        /// <value>lhs + rhs</value>
        /// <returns>
        /// The sum of the <paramref name="lhs"/> and <paramref name="rhs"/> matrixes.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the row count or column count of <paramref name="lhs"/> 
        /// does not equal the row count or column count of <paramref name="rhs"/>, respectively.
        /// </exception>
        IMatrix<TComponent> Add(IMatrix<TComponent> lhs, IMatrix<TComponent> rhs);

        /// <summary>
        /// Adds two vectors and returns the result.
        /// </summary>
        /// <param name="lhs">First vector to add.</param>
        /// <param name="rhs">Second vector to add.</param>
        /// <value>lhs + rhs</value>
        /// <returns>
        /// The sum of the <paramref name="lhs"/> and <paramref name="rhs"/> vectors.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the component count of <paramref name="lhs"/> 
        /// does not equal the component count of <paramref name="rhs"/>, respectively.
        /// </exception>
        IVector<TComponent> Add(IVector<TComponent> lhs, IVector<TComponent> rhs);

        /// <summary>
        /// Subtracts two matrixes and returns the result.
        /// </summary>
        /// <param name="lhs">Matrix on the left of the subtraction operation.</param>
        /// <param name="rhs">Matrix on the right of the subtraction operation.</param>
        /// <value>lhs - rhs</value>
        /// <returns>
        /// The difference of the <paramref name="lhs"/> and <paramref name="rhs"/> matrixes.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the row count or column count of <paramref name="lhs"/> 
        /// does not equal the row count or column count of <paramref name="rhs"/>, respectively.
        /// </exception>
        IMatrix<TComponent> Subtract(IMatrix<TComponent> lhs, IMatrix<TComponent> rhs);

        /// <summary>
        /// Subtracts two vectors and returns the result.
        /// </summary>
        /// <param name="lhs">Vector on the left of the subtraction operation.</param>
        /// <param name="rhs">Vector on the right of the subtraction operation.</param>
        /// <value>lhs - rhs</value>
        /// <returns>
        /// The difference of the <paramref name="lhs"/> and <paramref name="rhs"/> vectors.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the component count of <paramref name="lhs"/> 
        /// does not equal the component count of <paramref name="rhs"/>, respectively.
        /// </exception>
        IVector<TComponent> Subtract(IVector<TComponent> lhs, IVector<TComponent> rhs);

        /// <summary>
        /// Multiplies two matrixes and returns the result.
        /// </summary>
        /// <param name="lhs">Matrix on the left of the multiplication operation.</param>
        /// <param name="rhs">Matrix on the right of the multiplication operation.</param>
        /// <value>lhs * rhs</value>
        /// <returns>
        /// The product of multiplying <paramref name="lhs"/> by <paramref name="rhs"/>.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the column count of <paramref name="lhs"/> 
        /// does not equal the row count of <paramref name="rhs"/>.
        /// </exception>
        IMatrix<TComponent> Multiply(IMatrix<TComponent> lhs, IMatrix<TComponent> rhs);

        /// <summary>
        /// Multiplies two matrixes, with the result stored in the left matrix.
        /// </summary>
        /// <param name="lhs">Matrix on the left of the multiplication operation.</param>
        /// <param name="rhs">Matrix on the right of the multiplication operation.</param>
        /// <value>lhs * rhs</value>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the column count of <paramref name="lhs"/> 
        /// does not equal the row count of <paramref name="rhs"/>.
        /// </exception>
        void Multiply(ref IMatrix<TComponent> lhs, IMatrix<TComponent> rhs);

        /// <summary>
        /// Multiplies two matrixes, with the result stored in the right matrix.
        /// </summary>
        /// <param name="lhs">Matrix on the left of the multiplication operation.</param>
        /// <param name="rhs">Matrix on the right of the multiplication operation.</param>
        /// <value>lhs * rhs</value>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or if <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the column count of <paramref name="lhs"/> 
        /// does not equal the row count of <paramref name="rhs"/>.
        /// </exception>
        void Multiply(IMatrix<TComponent> lhs, ref IMatrix<TComponent> rhs);

        /// <summary>
        /// Multiplies a vector by a matrix, where the vector is represented in column form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="columnVector">The column vector to multiply.</param>
        /// <returns>The vector product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="columnVector"/> is null.
        /// </exception>
        IVector<TComponent> Multiply(IMatrix<TComponent> multiplier, IVector<TComponent> columnVector);

        /// <summary>
        /// Multiplies a vector by a matrix, where the vector is represented in row form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="rowVector">The row vector to multiply.</param>
        /// <returns>The vector product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="rowVector"/> is null.
        /// </exception>
        IVector<TComponent> Multiply(IVector<TComponent> rowVector, IMatrix<TComponent> multiplier);

        /// <summary>
        /// Multiplies a vector by a matrix, where the vector is represented in column form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="columnVector">The column vector to multiply.</param>
        /// <returns>The vector product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="columnVector"/> is null.
        /// </exception>
        void Multiply(IMatrix<TComponent> multiplier, TComponent[] columnVector);

        /// <summary>
        /// Multiplies a vector by a matrix, where the vector is represented in row form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="rowVector">The row vector to multiply.</param>
        /// <returns>The vector product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="rowVector"/> is null.
        /// </exception>
        void Multiply(TComponent[] rowVector, IMatrix<TComponent> multiplier);

        /// <summary>
        /// Multiplies a matrix by a series of matrixes, and returns the series of products.
        /// </summary>
        /// <param name="lhs">
        /// Matrix on the left of the multiplication operation.
        /// </param>
        /// <param name="rhs">
        /// A series of matrixes on the right of the multiplication operation.
        /// </param>
        /// <returns>
        /// An enumeration of the products of the <paramref name="lhs"/> 
        /// matrix multiplied by each <paramref name="rhs"/> matrix.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the column count of <paramref name="lhs"/> 
        /// does not equal the row count of <paramref name="rhs"/>.
        /// </exception>
        IEnumerable<IMatrix<TComponent>> Multiply(IMatrix<TComponent> lhs, IEnumerable<IMatrix<TComponent>> rhs);

        /// <summary>
        /// Multiplies a series of matrixes by another matrix, and returns the series of products.
        /// </summary>
        /// <param name="lhs">
        /// A series of matrixes on the left of the multiplication operation.
        /// </param>
        /// <param name="rhs">
        /// Matrix on the right of the multiplication operation.
        /// </param>
        /// <returns>
        /// An enumeration of the products of each <paramref name="lhs"/> matrix 
        /// multiplied by the <paramref name="rhs"/> matrix.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="lhs"/> is null or <paramref name="rhs"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// If the column count of <paramref name="lhs"/> 
        /// does not equal the row count of <paramref name="rhs"/>.
        /// </exception>
        IEnumerable<IMatrix<TComponent>> Multiply(IEnumerable<IMatrix<TComponent>> lhs, IMatrix<TComponent> rhs);

        /// <summary>
        /// Multiplies a series of vectors by a matrix, 
        /// where the vectors are represented in column form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="columnVectors">The column vector to multiply.</param>
        /// <returns>The vector product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="columnVectors"/> is null.
        /// </exception>
        IEnumerable<IVector<TComponent>> Multiply(IMatrix<TComponent> multiplier, IEnumerable<IVector<TComponent>> columnVectors);

        /// <summary>
        /// Multiplies a series of vectors by a matrix, 
        /// where the vectors are represented in row form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="rowVectors">The row vectors to multiply.</param>
        /// <returns>The vector products.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="rowVectors"/> is null.
        /// </exception>
        IEnumerable<IVector<TComponent>> Multiply(IEnumerable<IVector<TComponent>> rowVectors, IMatrix<TComponent> multiplier);

        /// <summary>
        /// Multiplies a series of vectors by a matrix, 
        /// where the vectors are represented in column form.
        /// </summary>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <param name="columnVectorsComponents">
        /// The column vectors to multiply as an enumeration of 
        /// arrays of components.
        /// </param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="columnVectorsComponents"/> is null.
        /// </exception>
        void Multiply(IMatrix<TComponent> multiplier, IEnumerable<TComponent[]> columnVectorsComponents);

        /// <summary>
        /// Multiplies a series of vectors by a matrix, 
        /// where the vectors are represented in row form.
        /// </summary>
        /// <param name="rowVectorsComponents">
        /// The row vectors to multiply as an enumeration of arrays of components.
        /// </param>
        /// <param name="multiplier">Matrix to multiply by.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="multiplier"/> is null or 
        /// <paramref name="rowVectorsComponents"/> is null.
        /// </exception>
        void Multiply(IEnumerable<TComponent[]> rowVectorsComponents, IMatrix<TComponent> multiplier);

        /// <summary>
        /// Multiplies a matrix by a scalar value.
        /// </summary>
        /// <param name="matrix">The matrix to multiply.</param>
        /// <param name="scalar">The scalar to multiply the matrix by.</param>
        /// <returns>The matrix product.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        IMatrix<TComponent> ScalarMultiply(IMatrix<TComponent> matrix, TComponent scalar);

        /// <summary>
        /// Computes the inverse of the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the inverse for.</param>
        /// <returns>
        /// The inverse of the given <paramref name="matrix"/>, if one exists. 
        /// If the matrix is non-square, the pseudo-inverse is returned.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        IMatrix<TComponent> Invert(IMatrix<TComponent> matrix);

        /// <summary>
        /// Negates a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to negate.</param>
        /// <returns>
        /// A matrix identical to <paramref name="matrix"/> except with each element negated.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        IMatrix<TComponent> Negate(IMatrix<TComponent> matrix);

        /// <summary>
        /// Performs the rotate linear operation on the given <paramref name="matrix"/>.
        /// </summary>
        /// <param name="matrix">Matrix to rotate.</param>
        /// <param name="axis">A vector describing the axis of rotation.</param>
        /// <param name="radians">The measure of the angle to rotate through.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null or <paramref name="axis"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the <paramref name="axis"/> vector has a 
        /// different number of components than the matrix rank.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown if the <paramref name="axis"/> vector has more 
        /// than one component with a value greater than 0.
        /// </exception>
        void Rotate(IMatrix<TComponent> matrix, IVector<TComponent> axis, Double radians);

        /// <summary>
        /// Performs the scale linear operation on a matrix.
        /// </summary>
        /// <param name="matrix">Matrix to scale.</param>
        /// <param name="scaleVector">A vector describing the magnitiudes of scale for each dimension.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null or <paramref name="scaleVector"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the <paramref name="scaleVector"/> has a different number of 
        /// components than the dimension of the linear transform submatrix of <paramref name="matrix"/>.
        /// </exception>
        void Scale(IMatrix<TComponent> matrix, IVector<TComponent> scaleVector);

        /// <summary>
        /// Performs the shear linear operation on a matrix.
        /// </summary>
        /// <param name="matrix">Matrix to shear.</param>
        /// <param name="shearVector">A vector describing the magnitiudes of shear for each dimension.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null or <paramref name="shearVector"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the <paramref name="shearVector"/> has a different number of 
        /// components than the dimension of the linear transform submatrix of <paramref name="matrix"/>.
        /// </exception>
        void Shear(IMatrix<TComponent> matrix, IVector<TComponent> shearVector);

        /// <summary>
        /// Performs the translate affine operation on a matrix.
        /// </summary>
        /// <param name="affineMatrix">Affine matrix to translate.</param>
        /// <param name="translateVector">A vector describing the magnitiudes of translations for each dimension.</param>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="affineMatrix"/> is null or <paramref name="translateVector"/> is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown if the <paramref name="translateVector"/> has a different number of 
        /// components than the dimension of the affine transform submatrix of <paramref name="affineMatrix"/>.
        /// </exception>
        void Translate(IMatrix<TComponent> affineMatrix, IVector<TComponent> translateVector);

        /// <summary>
        /// Computes the Frobenius norm on a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the norm over.</param>
        /// <value>
        /// The square root of the sum of the squares of each element 
        /// (or the square root of the sum of the squares 
        /// of the singluar values of the matrix).
        /// </value>
        /// <returns></returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double FrobeniusNorm(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes the one-norm (or Manhattan norm) on a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the norm over.</param>
        /// <value>
        /// The maximum value of the sum of the absolute value 
        /// of the elements of each column.
        /// </value>
        /// <returns>The one-norm.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double OneNorm(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes the two-norm on a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the norm over.</param>
        /// <value>
        /// The largest singular value for a matrix, or the Euclidean norm for a vector.
        /// </value>
        /// <returns>The two-norm.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double TwoNorm(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes the infinity-norm on a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the norm over.</param>
        /// <value>
        /// The maximum value of the sum of the absolute value 
        /// of the elements of each row.
        /// </value>
        /// <returns>The infinity-norm.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double InfinityNorm(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes the determinant for a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the determinant for.</param>
        /// <returns>The determinant of the matrix, if one exists.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        /// <exception cref="InvalidOperationException">
        /// Thrown if the matrix is not square.
        /// </exception>
        Double Determinant(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes the rank of a given matrix, disregarding negligable singluar values.
        /// </summary>
        /// <param name="matrix">The matrix to compute the rank for.</param>
        /// <returns>
        /// The rank of the given <paramref name="matrix"/>, not counting very small singular values.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Int32 Rank(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes the condition number for a matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the condition number for.</param>
        /// <value>The condition number is a measure of the relative error in a solution for the matrix.</value>
        /// <returns>The condition number for the given <paramref name="matrix"/>.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double Condition(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes the trace value of the given matrix.
        /// </summary>
        /// <param name="matrix">The matrix to compute the trace for.</param>
        /// <value>The sum of the values in the diagonal of the matrix.</value>
        /// <returns>The value of the trace.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        Double Trace(IMatrix<TComponent> matrix);

        /// <summary>
        /// Solves a linear system.
        /// </summary>
        /// <param name="a">Coefficient matrix.</param>
        /// <param name="b">Result matrix.</param>
        /// <returns>
        /// A matrix of solutions to the unknowns in the matrixes.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="a"/> is null or if <paramref name="b"/> is null.
        /// </exception>
        IMatrix<TComponent> Solve(IMatrix<TComponent> a, IMatrix<TComponent> b);

        /// <summary>
        /// Solves the transpose of the linear system.
        /// </summary>
        /// <param name="a">Coefficient matrix.</param>
        /// <param name="b">Result matrix.</param>
        /// <returns>
        /// A matrix of solutions to the unknowns in the transposed matrixes.
        /// </returns>
        /// Thrown if <paramref name="a"/> is null or if <paramref name="b"/> is null.
        IMatrix<TComponent> SolveTranspose(IMatrix<TComponent> a, IMatrix<TComponent> b);

        /// <summary>
        /// Computes the transpose of a given matrix.
        /// </summary>
        /// <param name="matrix">The matrix to find the transpose of.</param>
        /// <returns>A matrix which is the transpose of <paramref name="matrix"/>.</returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        IMatrix<TComponent> Transpose(IMatrix<TComponent> matrix);

        /// <summary>
        /// Sets the values of a <paramref name="target"/> matrix with those of
        /// a <paramref name="source"/> matrix.
        /// </summary>
        /// <param name="source">The matrix with the values to copy.</param>
        /// <param name="target">The matrix with the values to replace.</param>
        void SetMatrix(IMatrix<TComponent> source, IMatrix<TComponent> target);

        /// <summary>
        /// Computes an LU factorization for the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the LU factorization for.</param>
        /// <returns>
        /// An <see cref="ILUDecomposition{T, IMatrix<T>}"/> instance describing the factorization result.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        ILUDecomposition<TComponent> GetLUDecomposition(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes a QR factorization for the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the QR factorization for.</param>
        /// <returns>
        /// An <see cref="IQRDecomposition{T, IMatrix<T>}"/> instance describing the factorization result.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        IQRDecomposition<TComponent> GetQRDecomposition(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes a Cholesky factorization for the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the Cholesky factorization for.</param>
        /// <returns>
        /// An <see cref="ICholeskyDecomposition{T, IMatrix<T>}"/> instance describing the factorization result.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        ICholeskyDecomposition<TComponent> GetCholeskyDecomposition(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes a singluar value factorization (SVD) for the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the singluar value factorization for.</param>
        /// <returns>
        /// An <see cref="ISingularValueDecomposition{T, IMatrix<T>}"/> instance describing the factorization result.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        ISingularValueDecomposition<TComponent> GetSingularValueDecomposition(IMatrix<TComponent> matrix);

        /// <summary>
        /// Computes an eigenvalue factorization for the matrix.
        /// </summary>
        /// <param name="matrix">Matrix to compute the eigenvalue factorization for.</param>
        /// <returns>
        /// An <see cref="IEigenvalueDecomposition{T, IMatrix<T>}"/> instance describing the factorization result.
        /// </returns>
        /// <exception cref="ArgumentNullException">
        /// Thrown if <paramref name="matrix"/> is null.
        /// </exception>
        IEigenvalueDecomposition<TComponent> GetEigenvalueDecomposition(IMatrix<TComponent> matrix);
    }
}
